package com.cl.cloud.auth.config;

import com.cl.cloud.auth.exception.CustomWebResponseExceptionTranslator;
import lombok.AllArgsConstructor;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.oauth2.config.annotation.configurers.ClientDetailsServiceConfigurer;
import org.springframework.security.oauth2.config.annotation.web.configuration.AuthorizationServerConfigurerAdapter;
import org.springframework.security.oauth2.config.annotation.web.configuration.EnableAuthorizationServer;
import org.springframework.security.oauth2.config.annotation.web.configurers.AuthorizationServerEndpointsConfigurer;
import org.springframework.security.oauth2.config.annotation.web.configurers.AuthorizationServerSecurityConfigurer;
import org.springframework.security.oauth2.provider.CompositeTokenGranter;
import org.springframework.security.oauth2.provider.TokenGranter;
import org.springframework.security.oauth2.provider.token.TokenEnhancer;
import org.springframework.security.oauth2.provider.token.TokenEnhancerChain;
import org.springframework.security.oauth2.provider.token.TokenStore;
import org.springframework.security.oauth2.provider.token.store.JwtAccessTokenConverter;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

/**
 * @description: 这里是授权服务器的配置类
 * @author: liuzijian
 * @time: 2022-04-29 16:09
 */
@Configuration
@EnableAuthorizationServer // 这个注解必须加上,否则访问测试地址404
@AllArgsConstructor
public class CustomAuthorizationServerConfiguration extends AuthorizationServerConfigurerAdapter {

    private final PasswordEncoder passwordEncoder;

    @Qualifier("customUserDetailsServiceImpl")
    private final UserDetailsService userDetailsService;

    private final AuthenticationManager authenticationManager;
    private final CustomWebResponseExceptionTranslator customWebResponseExceptionTranslator;

    @Qualifier("jwtTokenStore")
    private final TokenStore tokenStore;

    @Qualifier("jwtTokenEnhancer")
    private final TokenEnhancer jwtTokenEnhancer;

    @Qualifier("jwtAccessTokenConverter")
    private final JwtAccessTokenConverter jwtAccessTokenConverter;


    /**
     * 配置授权模式（均可自定义）
     *
     * @param endpoints
     * @throws Exception
     */
    @Override
    public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {

        TokenEnhancerChain tokenEnhancerChain = new TokenEnhancerChain();
        //token增强（可以对token进行修改） 执行顺序根据add的顺序决定
        List<TokenEnhancer> enhancerList = new ArrayList<>();
        enhancerList.add(jwtAccessTokenConverter);
        enhancerList.add(jwtTokenEnhancer);
        tokenEnhancerChain.setTokenEnhancers(enhancerList);

        endpoints
                .tokenGranter(getCustomTokenGranter(endpoints))
                .tokenStore(tokenStore)//token存储  可以用来缓存token jwtToeknStore则不缓存 每次都生成新的token
                .userDetailsService(userDetailsService)
                .authenticationManager(authenticationManager) //使用密码模式需要配置
                .exceptionTranslator(customWebResponseExceptionTranslator)//自定义oauth2异常放回
                .tokenEnhancer(tokenEnhancerChain)//token增强调用链
                //.accessTokenConverter(jwtAccessTokenConverter);//token转换器
        ;
        //.allowedTokenEndpointRequestMethods(HttpMethod.GET, HttpMethod.POST); //支持GET,POST请求
    }

    /**
     * 配置客户端解析器
     *
     * @param clients
     * @throws Exception
     */
    @Override
    public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
        super.configure(clients);
        /**
         * 测试的时候用内存的方式配置
         * 正式使用可以用 {@link com.cl.cloud.auth.service.CustomClientDetailsServiceImpl} 配置
         */
        clients.inMemory()
                // 配置client_id
                .withClient("client")
                // 配置client_secret
                .secret(passwordEncoder.encode("123123"))
                //配置访问token的有效期
                .accessTokenValiditySeconds(3600)
                //配置刷新token的有效期
                .refreshTokenValiditySeconds(864000)
                //配置redirect_uri，用于授权成功后跳转
                .redirectUris("http://www.baidu.com")
                //配置申请的权限范围
                .scopes("all")
                /**
                 * 配置grant_type，表示授权类型
                 *
                 *  authorization_code：授权码模式
                 *  implicit：简化模式
                 *  password：密码模式
                 *  client_credentials: 客户端模式
                 *  refresh_token: 更新令牌
                 */
                .authorizedGrantTypes("authorization_code", "implicit", "password", "client_credentials");
    }

    // 配置允许表单认证
    @Override
    public void configure(AuthorizationServerSecurityConfigurer security) throws Exception {
        security.allowFormAuthenticationForClients();
    }

    /**
     * 自定义token granter
     * @param endpoints
     * @return
     */
    private TokenGranter getCustomTokenGranter(AuthorizationServerEndpointsConfigurer endpoints) {
        // 默认tokenGranter集合
        List<TokenGranter> granters = new ArrayList<>(Collections.singletonList(endpoints.getTokenGranter()));
        // 组合tokenGranter集合
        return new CompositeTokenGranter(granters);
    }


}
